package com.googlecode.jch.plugin.configuration;

import com.googlecode.jch.plugin.Icons;
import com.googlecode.jch.plugin.JCHUtil;
import com.intellij.execution.ui.ClassBrowser;
import com.intellij.ide.util.ClassFilter;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.Nls;

import javax.swing.*;
import java.util.Arrays;

/**
 * @author Iskander Akishev
 */
public class JCHConfigurable implements Configurable {
	private final Project project;
	private final JCHConfiguration configuration;
	private MyUI myUI;

	public JCHConfigurable(final Project project) {
		this.project = project;
		configuration = JCHConfiguration.getInstance(project);
	}

	@Nls
	public String getDisplayName() {
		return "Java Contest Helper";
	}

	public Icon getIcon() {
		return Icons.SOLUTION;
	}

	public String getHelpTopic() {
		return null;
	}

	public JComponent createComponent() {
		if (myUI == null)
			myUI = new MyUI(project);
		return myUI.myPanel;
	}

	public boolean isModified() {
		return myUI != null && (!Arrays.asList(myUI.inliningPackagesListPanel.getListItems()).equals(configuration.state.inliningPackages) ||
			!myUI.outputDirectoryField.getText().equals(configuration.state.outputDirectory) ||
			!myUI.inputReaderClassField.getText().equals(configuration.state.inputReaderClass)
		);
	}

	public void apply() throws ConfigurationException {
		myUI.inliningPackagesListPanel.applyTo(configuration.state.inliningPackages);
		configuration.state.outputDirectory = myUI.outputDirectoryField.getText();
		configuration.state.inputReaderClass = myUI.inputReaderClassField.getText();
	}

	public void reset() {
		myUI.inliningPackagesListPanel.resetFrom(configuration.state.inliningPackages);
		myUI.outputDirectoryField.setText(configuration.state.outputDirectory);
		myUI.inputReaderClassField.setText(configuration.state.inputReaderClass);
	}

	public void disposeUIResources() {
		myUI = null;
	}

	private static class MyUI {
		private JPanel myPanel;
		private PackagesAddDeleteListPanel inliningPackagesListPanel;
		private TextFieldWithBrowseButton.NoPathCompletion inputReaderClassField;
		private TextFieldWithBrowseButton outputDirectoryField;

		public MyUI(Project project) {
			new InputReaderClassBrowser(project).setField(inputReaderClassField);
			outputDirectoryField.addBrowseFolderListener("Output Directory", "Chose directory to put preprocessed solutions for submission", project, FileChooserDescriptorFactory.createSingleFolderDescriptor());
		}

		private void createUIComponents() {
			inliningPackagesListPanel = new PackagesAddDeleteListPanel("Inlining packages:", "Enter name of a package that should be inlined before submission:");
		}
	}

	private static class InputReaderClassBrowser extends ClassBrowser {
		private final Project project;
		private final GlobalSearchScope scope;

		private static final ClassFilter classFilter = new ClassFilter() {
			public boolean isAccepted(PsiClass psiClass) {
				return JCHUtil.isInputReaderClass(psiClass);
			}
		};

		private InputReaderClassBrowser(Project project) {
			super(project, "Choose Input Reader Class");
			this.project = project;
			scope = GlobalSearchScope.allScope(project);
		}

		@Override
		protected ClassFilter.ClassFilterWithScope getFilter() throws NoFilterException {
			return new ClassFilter.ClassFilterWithScope() {
				public GlobalSearchScope getScope() {
					return scope;
				}
				public boolean isAccepted(final PsiClass aClass) {
					return classFilter == null || classFilter.isAccepted(aClass);
				}
			};
		}

		@Override
		protected PsiClass findClass(String className) {
			return JavaPsiFacade.getInstance(project).findClass(className, scope);
		}
	}
}
